﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Borg.Framework
{
    public class CallCommand : ICommand
    {
        private readonly string[] _arguments = new[] { "Extension" };

        private string Call(string[] command)
        {
            if (command.Length < 2)
                return "Too few arguments.";

            if (!RuntimeCommands.ContainsArgument(command[1], _arguments))
                return string.Format("Invalid argument \"{0}\"", command[1]);

            var flag = false;

            if (command.Length < 3)
                return "Too few arguments";

            var objects = GetObjects(command);

            if (objects.Length == 0)
                return string.Format("{0} {1} not found", command[1], command[2]);

            if (command.Length == 3)
                flag = true;

            var builder = new StringBuilder();
            
            var type = objects[0] != null
                ? objects[0].GetType()
                : typeof(Runtime);
            
            if (flag)
            {
                foreach (MethodInfo info in type.GetMethods())
                    builder.AppendLine(info.Name);

                return builder.ToString();
            }

            var method = type.GetMethod(command[3]);

            if (method == null)
                return string.Format("Property \"{0}\" not found", command[3]);

            var parameters = new object[method.GetParameters().Length];

            foreach (var o in objects)
                method.Invoke(o, parameters);

            return builder.ToString();
        }

        public IEnumerable<string> GetArguments(string[] command, int pos)
        {
            string[] args = null;
            int i;

            switch (pos)
            {
                case 0:
                    return _arguments;

                case 1:
                    if (command.Length >= 2)
                    {
                        if (command[1] == "Extension")
                        {
                            args = new string[Runtime.Repository.ExtensionInfos.Count];

                            for (i = 0; i < args.Length; i++)
                                args[i] = Runtime.Repository.ExtensionInfos[i].Name;
                        }

                        return args;
                    }

                    return new string[0];

                case 2:
                    if (command.Length >= 3 && command[2] != "Runtime")
                    {
                        var objects = GetObjects(command);

                        if (objects.Length == 0)
                            return new string[0];

                        var methods = objects[0].GetType().GetMethods();
                        args = new string[methods.Length];

                        for (i = 0; i < args.Length; i++)
                            args[i] = methods[i].Name;

                        return args;
                    }

                    return new string[0];
            }

            return null;
        }

        private static object[] GetObjects(IList<string> command)
        {
            string arg;

            var repoElements =
                RuntimeCommands.Find(new[] { "ExtensionInfo", command[2] }, 0, out arg);

            if (repoElements.Length == 0)
                return new object[0];

            var obs = new object[repoElements.Length];

            for (var i = 0; i < obs.Length; i++)
                obs[i] = ((ExtensionInfo) repoElements[i]).Object;

            return obs;
        }

        private static string RuntimeProperty(IList<string> command)
        {
            if (command == null || command.Count < 3)
                return "  Property parameter missing";

            var eq = command[2].Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);

            if (eq.Length == 0)
                return "  Property parameter missing";

            var result = false;
            var flag = false;

            var format = string.Format("  Property {0}={{0}}", eq[0]);

            if (eq.Length > 1)
            {
                if (!bool.TryParse(eq[1], out result))
                    return string.Format("  Invalid property value: {0}", eq[1]);

                flag = true;
            }
            switch (eq[0])
            {
                case "AutoOpen":
                    if (flag)
                        Runtime.AutoOpen = result;

                    return string.Format(format, Runtime.AutoOpen);

                case "AutoRegister":
                    if (flag)
                        Runtime.AutoRegister = result;

                    return string.Format(format, Runtime.AutoRegister);

                case "AutoPlug":
                    if (flag)
                        Runtime.AutoPlug = result;

                    return string.Format(format, Runtime.AutoPlug);

                case "AutoRelease":
                    if (flag)
                        Runtime.AutoRelease = result;

                    return string.Format(format, Runtime.AutoRelease);

                case "LazyLoad":
                    if (flag)
                        Runtime.LazyLoad = result;

                    return string.Format(format, Runtime.LazyLoad);

                case "":
                    return "  Property parameter missing";
            }

            return string.Format("  Property {0} not found", eq[0]);
        }

        public CommandHandler Handler
        {
            get { return Call; }
        }

        public string Help
        {
            get { return "Help for command \"call\""; }
        }

        public string Name
        {
            get { return "call"; }
        }
    }
}

